﻿using Coolvis.Component;
using CPPEI.Coolzon.Configuration.Client;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace CPPEI.Coolzon.UI
{
    public class PartFactory
    {
        /// <summary>
        /// 组件名和类型的对应关系，方便以后创建组件实例
        /// </summary>
        static Dictionary<string, PartAssemblyInfo> s_partTypeDict = new Dictionary<string, PartAssemblyInfo>();

        public static Part CreatePart(Metadata.PartLibItem partLibItem)
        {
            if (partLibItem.Name == "Area")
            {
                return new AreaPart();
            }

            string partItemAssembly = partLibItem.Assembly;
            string partItemClass = partLibItem.Type;
            UI.Part part = null;
            try
            {
                string assemblyFile = string.Format("{0}{1}", AppDomain.CurrentDomain.BaseDirectory, partItemAssembly);
                if (!assemblyFile.EndsWith(".dll"))
                {
                    assemblyFile += ".dll";
                }
                Assembly assembly = Assembly.LoadFile(assemblyFile);
                object objPart = assembly.CreateInstance(partItemClass);

                part = (Part)objPart;
            }
            catch
            {
            }
            return part;
        }

        public static Part CreatePart(string type, string name)
        {
            Part part = null;
            if (type.ToUpper() == "SCENE")
            {
                part = new ScenePart();
            }
            else if (type.ToUpper() == "AREA")
            {
                part = new AreaPart();
            }
            else
            {
                try
                {
                    if (s_partTypeDict.ContainsKey(type))
                    {
                        PartAssemblyInfo partAssemblyInfo = s_partTypeDict[type];
                        object objPart = partAssemblyInfo.Assembly.CreateInstance(partAssemblyInfo.Type.FullName);
                        part = (Part)objPart;
                    }
                    else
                    {
                        string partLibName = string.Empty;
                        string partItemClass = string.Empty;
                        string partItemAssembly = string.Empty;

                        PartLibsConfig partLibsConfig = Config.PartLibs;
                        for (int partLibIndex = 0; partLibIndex < Config.PartLibs.PartLibs.Count; partLibIndex++)
                        {
                            PartLib lib = Config.PartLibs.PartLibs[partLibIndex];
                            string filePath = string.Format("{0}{1}{2}.xml", Config.PartLibs.PartLibsBaseAddress, Config.PartLibs.PartLibsDirectory, lib.Name);

                            if (filePath.EndsWith(".xml"))
                            {
                                XDocument xDoc = XDocument.Load(filePath);

                                List<XElement> xPartItemList = xDoc.Element("PartLib").Elements("PartItem").ToList();
                                for (int xIndex = 0; xIndex < xPartItemList.Count; xIndex++)
                                {
                                    XElement xPartItem = xPartItemList[xIndex];
                                    string partItemName = xPartItem.Attribute("Name").Value;
                                    if (partItemName == type)
                                    {
                                        partLibName = lib.Name;
                                        partItemClass = xPartItem.Attribute("Type").Value;
                                        partItemAssembly = xPartItem.Attribute("Assembly").Value;
                                        break;
                                    }
                                }
                            }

                            if (!string.IsNullOrEmpty(partItemClass))
                            {
                                break;
                            }
                        }

                        string assemblyFile = string.Format("{0}{1}", AppDomain.CurrentDomain.BaseDirectory, partItemAssembly);
                        if (!assemblyFile.EndsWith(".dll"))
                        {
                            assemblyFile += ".dll";
                        }
                        Assembly assembly = Assembly.LoadFile(assemblyFile);
                        Type partType = assembly.GetType(partItemClass);

                        s_partTypeDict.Add(type, new PartAssemblyInfo(assembly, partType));
                        object objPart = assembly.CreateInstance(partItemClass);

                        part = (Part)objPart;
                    }
                }
                catch (Exception ex)
                {
                    part = null;
                    Common.Logger.ErrorToTag("UI", "创建组件：{0}，类型：{1}失败，ex:{2}",
                        name,
                        type,
                        ex);
                }
            }
            if (part != null)
            {
                part.Name = name;
                part.XFullName = name;
            }
            return part;
        }

        /// <summary>
        /// [2.0新增]
        /// 创建组件实例
        /// </summary>
        /// <param name="nsUri"></param>
        /// <param name="tagName">标记名称</param>
        /// <param name="name">组件名称</param>
        /// <returns></returns>
        public static Part CreateInst(Coolvis.Metadata.PartNamespaceUri nsUri, string tagName, string name)
        {
            string typeString = string.Format("namespace={0};assembly={1};type={2}", nsUri.Namespace, nsUri.Assembly, tagName);
            Part part = null;
            try
            {
                if (s_partTypeDict.ContainsKey(typeString))
                {
                    PartAssemblyInfo partAssemblyInfo = s_partTypeDict[typeString];
                    object objPart = partAssemblyInfo.Assembly.CreateInstance(partAssemblyInfo.Type.FullName);
                    part = (Part)objPart;
                }
                else
                {
                    string partItemClass = string.Empty;
                    string partItemAssembly = nsUri.Assembly;

                    string assemblyFile = string.Format("{0}{1}", AppDomain.CurrentDomain.BaseDirectory, partItemAssembly);
                    if (!assemblyFile.EndsWith(".dll"))
                    {
                        assemblyFile += ".dll";
                    }
                    Assembly assembly = Assembly.LoadFile(assemblyFile);
                    Type[] partTypes = assembly.GetTypes();
                    for (int iofType = 0; iofType < partTypes.Length; iofType++)
                    {
                        Type partType = partTypes[iofType];
                        XmlTagAttribute xmlTagAttr = partType.GetCustomAttribute(typeof(XmlTagAttribute), true) as XmlTagAttribute;
                        if (xmlTagAttr != null && string.Equals(xmlTagAttr.Name, tagName))
                        {
                            partItemClass = partType.FullName;
                            s_partTypeDict.Add(typeString, new PartAssemblyInfo(assembly, partType));
                            object objPart = assembly.CreateInstance(partItemClass);

                            part = (Part)objPart;
                            break;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                part = null;
                Common.Logger.ErrorToTag("UI", "创建组件：{0}，name：{1}失败，ex:{2}",
                    tagName,
                    name,
                    ex);
            }
            if (part != null)
            {
                part.Name = name;
                part.XFullName = name;
            }
            return part;
        }

        public static Layout CreateLayout(string type)
        {
            if (type.ToUpper() == "DOCK")
            {
                return new DockLayout();
            }
            else if (type.ToUpper() == "HSTACK")
            {
                return new HStackLayout();
            }
            else if (type.ToUpper() == "VSTACK")
            {
                return new VStackLayout();
            }
            else if (type.ToUpper() == "ABSOLUTE")
            {
                return new AbsoluteLayout();
            }
            return null;
        }
    }

    class PartAssemblyInfo
    {
        public Assembly Assembly { get; set; }
        public Type Type { get; set; }
        public PartAssemblyInfo(Assembly assembly, Type type)
        {
            Assembly = assembly;
            Type = type;
        }
    }
}
